package eu.goldenak.ircbot;

import java.io.File;
import java.util.AbstractMap;
import java.util.HashMap;
import java.util.NoSuchElementException;
import java.util.Scanner;
import java.util.concurrent.ConcurrentHashMap;

/**
 * This class manages all configuration ever needed in the bot. This includes 
 * modules. This is done so that it's easy to monitor changes and provide 
 * multiple ways to change a setting without writing a special class for it
 * every single time.
 *
 * TODO:
 * 1. Monitor changes
 * 2. Store settings without conflicts between the main configuration and/or
 *    modules
 * 3. Some way to read and write settings internally (via methods) and loading
 *    it from configfiles
 * 4. Section support
 */
public class ConfigManager {
	/**
	 * The main hashtable holding all of the bot's configurations, including
	 * modules.
	 */
	private static AbstractMap <String, HashMap <String, String>> m_hmConfig = 
		new ConcurrentHashMap <String, HashMap <String, String>> ();
	
	/**
	 * This method will load up the critical configuration, which is needed by
	 * the bot to be able to start at all.
	 */
	public static void loadMainConfig () {
		try {
			loadConfigFile ("Main");
		} catch (Exception pException) {
			System.out.println ("Fatal error loading Main.cfg: " + pException);
			System.exit (1);
		}
	}
	
	/**
	 * Opens a file and parses the settings in it to a hashtable.
	 */
	public static void loadConfigFile (String sFileName) throws Exception {
		m_hmConfig.put (sFileName, new HashMap <String, String> ());
		
		File pFile = new File ("config", sFileName + ".cfg");
		if (!pFile.exists ()) {
			throw new Exception ("Configfile 'config/" + sFileName + ".cfg' not found.");
		}
		
		Scanner pScanner = new Scanner (pFile);
		while (pScanner.hasNextLine ()) {
			String sLine = pScanner.nextLine ().trim ();
			
			if (sLine.length () == 0 || sLine.startsWith ("//")) {
				// Comment or empty line, skip this line.
				continue;
			} else if (sLine.startsWith ("[") && sLine.endsWith ("]")) {
				// Section, [example]
				// This is going to be needed in the future, when multi-server
				// is going to be implemented.
				
				System.out.println (sLine.substring (1, sLine.length () - 1));
				continue;
			} else {
				Scanner pLineScan = new Scanner (sLine).useDelimiter ("\\s*=\\s*");
			
				if (pLineScan.hasNext ()) {
					// Remove excess whitespace.
					String sKey = pLineScan.next ().trim ();
					
					if (pLineScan.hasNext ()) {
						// Key and value.
						set (sFileName, sKey, pLineScan.next ().trim ());
					} else {
						// Key, but no value. Slackers.
						set (sFileName, sKey, "");
					}
				}
			}
		}
	}
	
	/**
	 * Get.
	 */
	public static String get (String sModule, String sKey) {
		if (getModule (sModule).containsKey (sKey)) {
			return getModule (sModule).get (sKey);
		} else {
			throw new NoSuchElementException (sKey);
		}
	}
	
	/**
	 * Set.
	 */
	public static void set (String sModule, String sKey, String sValue) {
		m_hmConfig.get (sModule).put (sKey, sValue);
	}
	
	/**
	 * Get the configuration of an entire module.
	 */
	public static HashMap <String, String> getModule (String sModule) {
		if (m_hmConfig.containsKey (sModule)) {
			return m_hmConfig.get (sModule);
		} else {
			throw new NoSuchElementException (sModule);
		}
	}
}